<html><head><meta charset="utf-8"/><title>单向绑定</title></head><body><h1>单向绑定</h1><div class="x-wiki-content x-main-content">
 <p>
  MVVM就是在前端页面上，应用了扩展的MVC模式，我们关心Model的变化，MVVM框架自动把Model的变化映射到DOM结构上，这样，用户看到的页面内容就会随着Model的变化而更新。
 </p>
 <p>
  例如，我们定义好一个JavaScript对象作为Model，并且把这个Model的两个属性绑定到DOM节点上：
 </p>
 <p>
  <img alt="mvvm-bind" data-src="/files/attachments/1109447726333536/l" src="https://www.liaoxuefeng.com/files/attachments/1109447726333536/l"/>
 </p>
 <p>
  经过MVVM框架的自动转换，浏览器就可以直接显示Model的数据了：
 </p>
 <p>
  <img alt="mvvm-result" data-src="/files/attachments/1109447696943168/l" src="https://www.liaoxuefeng.com/files/attachments/1109447696943168/l"/>
 </p>
 <p>
  现在问题来了：MVVM框架哪家强？
 </p>
 <p>
  目前，常用的MVVM框架有：
 </p>
 <p>
  <a href="https://angularjs.org/">
   Angular
  </a>
  ：Google出品，名气大，但是很难用；
 </p>
 <p>
  <a href="http://backbonejs.org/">
   Backbone.js
  </a>
  ：入门非常困难，因为自身API太多；
 </p>
 <p>
  <a href="http://emberjs.com/">
   Ember
  </a>
  ：一个大而全的框架，想写个Hello world都很困难。
 </p>
 <p>
  我们选择MVVM的目标应该是入门容易，安装简单，能直接在页面写JavaScript，需要更复杂的功能时又能扩展支持。
 </p>
 <p>
  所以，综合考察，最佳选择是
  <a href="http://weibo.com/p/1005051761511274">
   尤雨溪
  </a>
  大神开发的MVVM框架：
  <a href="http://vuejs.org/">
   Vue.js
  </a>
 </p>
 <p>
  目前，Vue.js的最新版本是2.0，我们会使用2.0版本作为示例。
 </p>
 <p>
  我们首先创建基于koa的Node.js项目。虽然目前我们只需要在HTML静态页面中编写MVVM，但是很快我们就需要和后端API进行交互，因此，要创建基于koa的项目结构如下：
 </p>
 <pre><code>hello-vue/
|
+- .vscode/
|  |
|  +- launch.json &lt;-- VSCode 配置文件
|
+- app.js &lt;-- koa app
|
+- static-files.js &lt;-- 支持静态文件的koa middleware
|
+- package.json &lt;-- 项目描述文件
|
+- node_modules/ &lt;-- npm安装的所有依赖包
|
+- static/ &lt;-- 存放静态资源文件
   |
   +- css/ &lt;-- 存放bootstrap.css等
   |
   +- fonts/ &lt;-- 存放字体文件
   |
   +- js/ &lt;-- 存放各种js文件
   |
   +- index.html &lt;-- 使用MVVM的静态页面
</code></pre>
 <p>
  这个Node.js项目的主要目的是作为服务器输出静态网页，因此，
  <code>
   package.json
  </code>
  仅需要如下依赖包：
 </p>
 <pre><code>"dependencies": {
    "koa": "2.0.0",
    "mime": "1.3.4",
    "mz": "2.4.0"
}
</code></pre>
 <p>
  使用
  <code>
   npm install
  </code>
  安装好依赖包，然后启动
  <code>
   app.js
  </code>
  ，在
  <code>
   index.html
  </code>
  文件中随便写点内容，确保浏览器可以通过
  <code>
   http://localhost:3000/static/index.html
  </code>
  访问到该静态文件。
 </p>
 <p>
  紧接着，我们在
  <code>
   index.html
  </code>
  中用Vue实现MVVM的一个简单例子。
 </p>
 <h3>
  安装Vue
 </h3>
 <p>
  安装Vue有很多方法，可以用npm或者webpack。但是我们现在的目标是尽快用起来，所以最简单的方法是直接在HTML代码中像引用jQuery一样引用Vue。可以直接使用CDN的地址，例如：
 </p>
 <pre><code>&lt;script src="https://unpkg.com/vue@2.0.1/dist/vue.js"&gt;&lt;/script&gt;
</code></pre>
 <p>
  也可以把
  <code>
   vue.js
  </code>
  文件下载下来，放到项目的
  <code>
   /static/js
  </code>
  文件夹中，使用本地路径：
 </p>
 <pre><code>&lt;script src="/static/js/vue.js"&gt;&lt;/script&gt;
</code></pre>
 <p>
  这里需要注意，
  <code>
   vue.js
  </code>
  是未压缩的用于开发的版本，它会在浏览器console中输出很多有用的信息，帮助我们调试代码。当开发完毕，需要真正发布到服务器时，应该使用压缩过的
  <code>
   vue.min.js
  </code>
  ，它会移除所有调试信息，并且文件体积更小。
 </p>
 <h3>
  编写MVVM
 </h3>
 <p>
  下一步，我们就可以在HTML页面中编写JavaScript代码了。我们的Model是一个JavaScript对象，它包含两个属性：
 </p>
 <pre><code>{
    name: 'Robot',
    age: 15
}
</code></pre>
 <p>
  而负责显示的是DOM节点可以用
  <code>
   {{ name }}
  </code>
  和
  <code>
   {{ age}}
  </code>
  来引用Model的属性：
 </p>
 <pre><code>&lt;div id="vm"&gt;
    &lt;p&gt;Hello, {{ name }}!&lt;/p&gt;
    &lt;p&gt;You are {{ age }} years old!&lt;/p&gt;
&lt;/div&gt;
</code></pre>
 <p>
  最后一步是用Vue把两者关联起来。
  <em>
   要特别注意的是
  </em>
  ，在
  <code>
   &lt;head&gt;
  </code>
  内部编写的JavaScript代码，需要用jQuery把MVVM的初始化代码推迟到页面加载完毕后执行，否则，直接在
  <code>
   &lt;head&gt;
  </code>
  内执行MVVM代码时，DOM节点尚未被浏览器加载，初始化将失败。正确的写法如下：
 </p>
 <pre><code>&lt;html&gt;
&lt;head&gt;

&lt;!-- 引用jQuery --&gt;
&lt;script src="/static/js/jquery.min.js"&gt;&lt;/script&gt;

&lt;!-- 引用Vue --&gt;
&lt;script src="/static/js/vue.js"&gt;&lt;/script&gt;

&lt;script&gt;
// 初始化代码:
$(function () {
    var vm = new Vue({
        el: '#vm',
        data: {
            name: 'Robot',
            age: 15
        }
    });
    window.vm = vm;
});
&lt;/script&gt;

&lt;/head&gt;

&lt;body&gt;

    &lt;div id="vm"&gt;
        &lt;p&gt;Hello, {{ name }}!&lt;/p&gt;
        &lt;p&gt;You are {{ age }} years old!&lt;/p&gt;
    &lt;/div&gt;

&lt;/body&gt;
&lt;html&gt;
</code></pre>
 <p>
  我们创建一个VM的核心代码如下：
 </p>
 <pre><code>var vm = new Vue({
    el: '#vm',
    data: {
        name: 'Robot',
        age: 15
    }
});
</code></pre>
 <p>
  其中，
  <code>
   el
  </code>
  指定了要把Model绑定到哪个DOM根节点上，语法和jQuery类似。这里的
  <code>
   '#vm'
  </code>
  对应ID为
  <code>
   vm
  </code>
  的一个
  <code>
   &lt;div&gt;
  </code>
  节点：
 </p>
 <pre><code>&lt;div id="vm"&gt;
    ...
&lt;/div&gt;
</code></pre>
 <p>
  在该节点以及该节点内部，就是Vue可以操作的View。Vue可以自动把Model的状态映射到View上，但是
  <em>
   不能
  </em>
  操作View范围之外的其他DOM节点。
 </p>
 <p>
  然后，
  <code>
   data
  </code>
  属性指定了Model，我们初始化了Model的两个属性
  <code>
   name
  </code>
  和
  <code>
   age
  </code>
  ，在View内部的
  <code>
   &lt;p&gt;
  </code>
  节点上，可以直接用
  <code>
   {{ name }}
  </code>
  引用Model的某个属性。
 </p>
 <p>
  一切正常的话，我们在浏览器中访问
  <code>
   http://localhost:3000/static/index.html
  </code>
  ，可以看到页面输出为：
 </p>
 <pre><code>Hello, Robot!
You are 15 years old!
</code></pre>
 <p>
  如果打开浏览器console，因为我们用代码
  <code>
   window.vm = vm
  </code>
  ，把VM变量绑定到了window对象上，所以，可以直接修改VM的Model：
 </p>
 <pre><code>window.vm.name = 'Bob'
</code></pre>
 <p>
  执行上述代码，可以观察到页面立刻发生了变化，原来的
  <code>
   Hello, Robot!
  </code>
  自动变成了
  <code>
   Hello, Bob!
  </code>
  。Vue作为MVVM框架会自动监听Model的任何变化，在Model数据变化时，更新View的显示。这种Model到View的绑定我们称为单向绑定。
 </p>
 <p>
  经过CSS修饰后的页面如下：
 </p>
 <p>
  <img alt="hello-vue" data-src="/files/attachments/1109471421336064/l" src="https://www.liaoxuefeng.com/files/attachments/1109471421336064/l"/>
 </p>
 <p>
  可以在页面直接输入JavaScript代码改变Model，并观察页面变化。
 </p>
 <h3>
  单向绑定
 </h3>
 <p>
  在Vue中，可以直接写
  <code>
   {{ name }}
  </code>
  绑定某个属性。如果属性关联的是对象，还可以用多个
  <code>
   .
  </code>
  引用，例如，
  <code>
   {{ address.zipcode }}
  </code>
  。
 </p>
 <p>
  另一种单向绑定的方法是使用Vue的指令
  <code>
   v-text
  </code>
  ，写法如下：
 </p>
 <pre><code>&lt;p&gt;Hello, &lt;span v-text="name"&gt;&lt;/span&gt;!&lt;/p&gt;
</code></pre>
 <p>
  这种写法是把指令写在HTML节点的属性上，它会被Vue解析，该节点的文本内容会被绑定为Model的指定属性，注意不能再写双花括号
  <code>
   {{ }}
  </code>
  。
 </p>
 <h3>
  参考源码
 </h3>
 <p>
  <a href="https://github.com/michaelliao/learn-javascript/tree/master/samples/node/web/vue/hello-vue">
   hello-vue
  </a>
 </p>
</div>
</body></html>